﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace VectorPicsEditor
{
    using System.Windows;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using VectorPicsEditor.Helpers;
    using VectorPicsEditor.Properties;

    public struct WorkFile
    {
        public string path;
        public string ext;
    }

    public partial class Page : UserControl
    {
        private CanvasWrapper canvasWrapper;
        private WorkFile? file;
        private int imagesCount;

        public Page()
        {
            InitializeComponent();
            this.canvasWrapper = new CanvasWrapper(this.propertiesBar);
            this.elementHost.Child = this.canvasWrapper;

            this.canvasWrapper.Canvas.MouseMove += this.CanvasMousePositionChanged;
            this.canvasWrapper.Canvas.MouseLeave += this.CanvasMouseLeave;
            file = null;
            this.canvasWrapper.Changed = false;
            imagesCount = 1;
            propertiesBar.DataBindings.Add("BackColor", Settings.Default, "WrapperColor", false, DataSourceUpdateMode.OnPropertyChanged);
            panelHost.DataBindings.Add("BackColor", Settings.Default, "WorkspaceColor", false, DataSourceUpdateMode.OnPropertyChanged);
        }

        public void SetCanvasSize(double canvasWidth, double canvasHeight)
        {
            double heightKoef = canvasHeight / this.canvasWrapper.CanvasHeight;
            double widthKoef = canvasWidth / this.canvasWrapper.CanvasWidth;
            this.canvasWrapper.ResizeCanvasElements(widthKoef, heightKoef);
            this.canvasWrapper.CanvasHeight = canvasHeight;
            this.canvasWrapper.CanvasWidth = canvasWidth;
            this.canvasWrapper.Changed = true;
        }

        public void ForgetCanvasChanges()
        {
            this.canvasWrapper.Changed = false;
        }

        public void ChangeBackGround()
        {
            ColorDialog dlg = new ColorDialog();
            var result = dlg.ShowDialog();
            if (result == DialogResult.OK)
            {
                 canvasWrapper.ChangeBackGround(Converter.ConvertColor(dlg.Color));
            }
        }

        public string SaveAs()
        {
            // Configure save file dialog box
            Microsoft.Win32.SaveFileDialog saveFileDlg = new Microsoft.Win32.SaveFileDialog();
            saveFileDlg.FileName = "NewImage"; // Default file name
            saveFileDlg.DefaultExt = ".chtp"; // Default file extension
            saveFileDlg.Filter = " JPG(*.jpg)|*.jpg|BMP (*.bmp)|*.bmp| PNG(*.png)|*.png | Specific program format(*.chtp)|*.chtp"; // Filter files by extension

            // Show save file dialog box
            Nullable<bool> result = saveFileDlg.ShowDialog();

            // Process save file dialog box results
            if (result == true)
            {
                // Save document
                string filename = saveFileDlg.FileName;
                string ext = System.IO.Path.GetExtension(filename).ToLower();
                this.file = new WorkFile { ext = ext, path = filename };
                return this.Save();
            }
            else
            {
                return "#";
            }
        }

        public string Save()
        {
            if (this.file == null)
            {
                return this.SaveAs();
            }
            this.canvasWrapper.RemoveSelection();
            if (this.file.Value.ext == ".jpg" || this.file.Value.ext == ".bmp" || this.file.Value.ext == ".png")
            {
                // Save current canvas transform
                Transform transform = this.canvasWrapper.Canvas.LayoutTransform;
                // reset current transform (in case it is scaled or rotated)
                this.canvasWrapper.Canvas.LayoutTransform = null;

                RenderTargetBitmap rtb = new RenderTargetBitmap((int)this.canvasWrapper.Canvas.RenderSize.Width,
                (int)this.canvasWrapper.Canvas.RenderSize.Height, 96d, 96d, System.Windows.Media.PixelFormats.Default);
                rtb.Render(this.canvasWrapper.Canvas);

                BitmapEncoder encoder = new JpegBitmapEncoder();
                switch (this.file.Value.ext)
                {
                    case ".jpg":
                        encoder = new JpegBitmapEncoder();
                        break;
                    case ".bmp":
                        encoder = new BmpBitmapEncoder();
                        break;
                    case ".png":
                        encoder = new PngBitmapEncoder();
                        break;
                }
                encoder.Frames.Add(BitmapFrame.Create(rtb));

                using (System.IO.FileStream fs = new System.IO.FileStream(this.file.Value.path, System.IO.FileMode.Create))
                {
                    encoder.Save(fs);
                    fs.Close();
                }
                this.canvasWrapper.Canvas.LayoutTransform = transform;
            }
            else //chtp
            {
                bool hasImage = false;
                if (this.canvasWrapper.Canvas.Background is ImageBrush)
                {
                    hasImage = true;
                    ImageBrush tmp = this.canvasWrapper.Canvas.Background as ImageBrush;
                    Uri  curUri = (tmp.ImageSource as BitmapImage).UriSource;
                    

                    //create folder
                    string folderPath = this.file.Value.path.Replace(this.file.Value.ext, "") + "_resources";
                    System.IO.Directory.CreateDirectory(folderPath);
                    string filename = curUri.OriginalString.Split('\\').Last();
                    string copyFile = folderPath + "\\" + filename;
                    if(!System.IO.File.Exists(copyFile))
                        System.IO.File.Copy(curUri.OriginalString , copyFile);

                    curUri = new Uri(copyFile, UriKind.Absolute);
                    
                    BitmapImage src = new BitmapImage();
                    src.BeginInit();
                    src.UriSource = curUri;
                    src.EndInit();

                    ImageBrush ib = new ImageBrush();
                    ib.ImageSource = src;
                    ib.Stretch = Stretch.Fill;
                    this.canvasWrapper.Canvas.Background = ib;
                }
                foreach (FrameworkElement elem in this.canvasWrapper.Canvas.Children)
                {
                    if (elem is System.Windows.Controls.Image)
                    {
                        BitmapImage tmp = (elem as System.Windows.Controls.Image).Source as BitmapImage;
                        Uri curUri = tmp.UriSource;

                        //create folder
                        string folderPath = this.file.Value.path.Replace(this.file.Value.ext, "") + "_resources";
                        if (!hasImage)
                        {
                            hasImage = true;
                            System.IO.Directory.CreateDirectory(folderPath);
                        }
                        string filename = curUri.OriginalString.Split('\\').Last();
                        string copyFile = folderPath + "\\" + filename;
                        if (!System.IO.File.Exists(copyFile))
                            System.IO.File.Copy(curUri.OriginalString, copyFile);

                        curUri = new Uri(copyFile, UriKind.Absolute);

                        BitmapImage src = new BitmapImage();
                        src.BeginInit();
                        src.UriSource = curUri;
                        src.EndInit();

                        (elem as System.Windows.Controls.Image).Stretch = Stretch.Fill;
                        (elem as System.Windows.Controls.Image).Source = src;
                    }
                }
                string savedCanvas = System.Windows.Markup.XamlWriter.Save(canvasWrapper.Canvas);
                using (System.IO.FileStream fs = new System.IO.FileStream(this.file.Value.path, System.IO.FileMode.Create))
                {
                    byte[] info = new UTF8Encoding(true).GetBytes(savedCanvas);
                    fs.Write(info, 0, info.Length);
                    fs.Close();
                }
            }
            this.canvasWrapper.Changed = false;
            return this.file.Value.path;
        }

        public void ImportImage()
        {
            // Create OpenFileDialog
            Microsoft.Win32.OpenFileDialog openFileDlg = new Microsoft.Win32.OpenFileDialog();

            // Set filter for file extension and default file extension
            openFileDlg.DefaultExt = ".jpg";
            openFileDlg.Filter = "Image Files (*.bmp, *.jpg, *.png)|*.bmp;*.jpg;*.png";

            // Display OpenFileDialog by calling ShowDialog method
            Nullable<bool> result = openFileDlg.ShowDialog();

            // Get the selected file name and display in a TextBox
            if (result == true)
            {
                // Open document
                string filename = openFileDlg.FileName;
                string ext = System.IO.Path.GetExtension(filename).ToLower();
                BitmapImage src = new BitmapImage();
                src.BeginInit();
                src.UriSource = new Uri(filename, UriKind.Absolute);
                src.EndInit();

                System.Windows.Controls.Image img = new System.Windows.Controls.Image();
                img.Source = src;
                img.Width = src.Width;
                img.Height = src.Height;
                img.Stretch = Stretch.Fill;
                System.Windows.Controls.Canvas.SetLeft(img, 0);
                System.Windows.Controls.Canvas.SetTop(img, 0);

                ShapeWrapper sh = new ShapeWrapper(img, "Image " + imagesCount++);
                this.canvasWrapper.AddShape(sh);
                this.canvasWrapper.Canvas.Children.Add(img);
                this.canvasWrapper.Changed = false;
            }
        }

        public string Open()
        {
            // Create OpenFileDialog
            Microsoft.Win32.OpenFileDialog openFileDlg = new Microsoft.Win32.OpenFileDialog();

            // Set filter for file extension and default file extension
            openFileDlg.DefaultExt = ".jpg";
            openFileDlg.Filter = "Image Files (*.bmp, *.jpg, *.png, *.chtp)|*.bmp;*.jpg;*.png;*.chtp";

            // Display OpenFileDialog by calling ShowDialog method
            Nullable<bool> result = openFileDlg.ShowDialog();

            // Get the selected file name and display in a TextBox
            if (result == true)
            {
                // Open document
                string filename = openFileDlg.FileName;
                string ext = System.IO.Path.GetExtension(filename).ToLower();

                file = new WorkFile { path = filename, ext = ext };
                if (ext == ".jpg" || ext == ".bmp" || ext == ".png")
                {
                    BitmapImage src = new BitmapImage();
                    src.BeginInit();
                    src.UriSource = new Uri(filename, UriKind.Absolute);
                    src.EndInit();

                    this.canvasWrapper.CanvasHeight = src.PixelHeight;
                    this.canvasWrapper.CanvasWidth = src.PixelWidth;

                    ImageBrush ib = new ImageBrush();
                    ib.ImageSource = src;
                    ib.Stretch = Stretch.Fill;
                    this.canvasWrapper.Canvas.Background = ib;
                    
                }
                else  //chtp
                {
                    using (System.IO.FileStream fs = System.IO.File.OpenRead(filename))
                    {
                        byte[] b = new byte[fs.Length];
                        UTF8Encoding temp = new UTF8Encoding(true);
                        fs.Read(b, 0, b.Length);
                        string content = temp.GetString(b);
                        //parse images and image brushes and replase uri to right path
                        System.IO.StringReader stringReader = new System.IO.StringReader(content);
                        System.Xml.XmlReader xmlReader = System.Xml.XmlReader.Create(stringReader);
                        List<BitmapImage> imgs = new List<BitmapImage>();
                        Dictionary<string, string> replaceNames = new Dictionary<string, string>();
                        int nameLen = filename.Split('\\').Last().Length;
                        string path = filename.Substring(0, filename.Length - nameLen);
                        path = path + filename.Split('\\').Last().Replace(ext, "") + "_resources\\";
                        while (xmlReader.Read())
                        {
                            if (xmlReader.Name.Equals("Image") && (xmlReader.NodeType == System.Xml.XmlNodeType.Element))
                            {
                                string str = xmlReader.GetAttribute("Source");
                                str = str.Remove(0, 8).Replace('/', '\\');
                                str = str.Split('\\').Last();
                                str = path + str;
                                BitmapImage src = new BitmapImage();
                                src.BeginInit();
                                src.UriSource = new Uri(str, UriKind.Absolute);
                                src.EndInit();
                                imgs.Add(src);
                                replaceNames.Add(xmlReader.GetAttribute("Source"), @"file:///" + str.Replace('\\', '/'));
                            }
                            else if (xmlReader.Name.Equals("ImageBrush") && (xmlReader.NodeType == System.Xml.XmlNodeType.Element))
                            {
                                string str = xmlReader.GetAttribute("ImageSource");
                                str = str.Remove(0, 8).Replace('/', '\\');
                                str = str.Split('\\').Last();
                                str = path + str;
                                replaceNames.Add(xmlReader.GetAttribute("ImageSource"), @"file:///" + str.Replace('\\', '/'));
                            }
                        }
                        foreach(KeyValuePair<string,string> pr in replaceNames)
                        {
                            content = content.Replace(pr.Key, pr.Value);
                        }
                        //
                        stringReader = new System.IO.StringReader(content);
                        xmlReader = System.Xml.XmlReader.Create(stringReader);
                        System.Windows.Controls.Canvas loaded = (System.Windows.Controls.Canvas)System.Windows.Markup.XamlReader.Load(xmlReader);
                        this.canvasWrapper.CanvasHeight = loaded.Height;
                        this.canvasWrapper.CanvasWidth = loaded.Width;
                        this.canvasWrapper.Canvas.Children.Clear();
                        ////Load background
                        if (loaded.Background is ImageBrush && (loaded.Background as ImageBrush).ImageSource is BitmapFrame)
                        {
                            stringReader = new System.IO.StringReader(content);
                            xmlReader = System.Xml.XmlReader.Create(stringReader);
                            while (xmlReader.Read())
                            {
                                if (xmlReader.Name.Equals("ImageBrush") && (xmlReader.NodeType == System.Xml.XmlNodeType.Element))
                                {
                                    string str = xmlReader.GetAttribute("ImageSource");
                                    str = str.Remove(0, 8).Replace('/','\\');
                                    BitmapImage src = new BitmapImage();
                                    src.BeginInit();
                                    src.UriSource = new Uri(str, UriKind.Absolute);
                                    src.EndInit();

                                    ImageBrush ib = new ImageBrush();
                                    ib.ImageSource = src;
                                    ib.Stretch = Stretch.Fill;
                                    this.canvasWrapper.Canvas.Background = ib;
                                    break;
                                }
                            }
                        }
                        else
                        {
                            this.canvasWrapper.Canvas.Background = loaded.Background;
                        }

                        UIElement[] arr = new UIElement[loaded.Children.Count];
                        loaded.Children.CopyTo(arr, 0);
                        loaded.Children.Clear();
                        int imgIndex = 0;
                        foreach (FrameworkElement elem in arr)
                        {
                            if ((elem is System.Windows.Controls.TextBox))
                                continue;
                            if (elem is System.Windows.Controls.Image)
                            {
                                (elem as System.Windows.Controls.Image).Source = imgs[imgIndex++];
                            }
                            ShapeWrapper sh = new ShapeWrapper(elem, elem.Name);
                            this.canvasWrapper.AddShape(sh);
                            this.canvasWrapper.Canvas.Children.Add(elem);
                        }
                        this.canvasWrapper.RemoveSelection();
                    }
                }
                this.canvasWrapper.Changed = false;
                return file.Value.path;
            }
            else
            {
                this.canvasWrapper.Changed = false;
                return "#";
            }
        }

        public Size GetCanvasSize()
        {
            Size toRet = new Size(this.canvasWrapper.CanvasWidth, this.canvasWrapper.CanvasHeight);
            return toRet;
        }

        public void StartDrawing(ShapeType shapeType)
        {
            this.canvasWrapper.StartDrawing(shapeType);
        }

        public void CanvasMousePositionChanged(object sender, System.Windows.Input.MouseEventArgs e)
        {
            Point pos = e.GetPosition(this.canvasWrapper.Canvas);
            this.cursorPositionStatusLabel.Text = "Cursor position: X: " + pos.X + " Y: " + pos.Y;
        }

        public void CanvasMouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
        {
            this.cursorPositionStatusLabel.Text = "Cursor position: ";
        }

        public void Remove()
        {
            if (this.canvasWrapper.Changed)
            {
                if (MessageBoxResult.Yes ==  MessageBox.Show("Do you want to save changes before closing?", "PicsEditor", MessageBoxButton.YesNo, MessageBoxImage.None, MessageBoxResult.No))
                {
                    try
                    {
                        this.Save();
                    }
                    catch(Exception)
                    {}
                }
            }
        }

        public void CopyToClipboard()
        {
            // Save current canvas transform
            Transform transform = this.canvasWrapper.Canvas.LayoutTransform;
            // reset current transform (in case it is scaled or rotated)
            this.canvasWrapper.Canvas.LayoutTransform = null;

            RenderTargetBitmap rtb = new RenderTargetBitmap((int)this.canvasWrapper.Canvas.RenderSize.Width,
            (int)this.canvasWrapper.Canvas.RenderSize.Height, 96d, 96d, System.Windows.Media.PixelFormats.Default);
            rtb.Render(this.canvasWrapper.Canvas);

            BitmapEncoder encoder = new PngBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(rtb));

            using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
            {
                encoder.Save(ms);

                this.canvasWrapper.Canvas.LayoutTransform = transform;
                System.Drawing.Image img = System.Drawing.Image.FromStream(ms);
                System.Windows.Forms.Clipboard.SetImage(img);
                ms.Close();
            }
        }

        public void LoadFromClipboard()
        {
            if (System.Windows.Forms.Clipboard.ContainsImage())
            {
                string bufPath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "Buffer");
                if (!System.IO.Directory.Exists(bufPath))
                    System.IO.Directory.CreateDirectory(bufPath);
                string filename = System.IO.Path.GetRandomFileName() + ".png";
                filename = System.IO.Path.Combine(bufPath, filename);
                //if (!System.IO.File.Exists(filename))
                //    System.IO.File.Create(filename);
                
                System.Windows.Forms.Clipboard.GetImage().Save(filename);
                BitmapImage src = new BitmapImage();
                src.BeginInit();
                src.UriSource = new Uri(filename, UriKind.Absolute);
                src.EndInit();

                System.Windows.Controls.Image img = new System.Windows.Controls.Image();
                img.Source = src;
                img.Width = src.Width;
                img.Height = src.Height;
                img.Stretch = Stretch.Fill;
                System.Windows.Controls.Canvas.SetLeft(img, 0);
                System.Windows.Controls.Canvas.SetTop(img, 0);

                ShapeWrapper sh = new ShapeWrapper(img, "Image " + imagesCount);
                this.canvasWrapper.AddShape(sh);
                this.canvasWrapper.Canvas.Children.Add(img);
                this.canvasWrapper.Changed = false;
            }
            
        }
    }
}
